package com.edu.internship.util;

import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Objects;

/**
 * code is far away from bug with the animal protecting
 *
 * @author lishiquan
 * @description 日期工具类
 * @date Create in 2018/2/26 11:10
 */
public class DateUtils {

    private DateUtils() {
    }

    public static String dateFormatter(Date date, String formatter) {
        return new SimpleDateFormat(formatter).format(date);
    }

    /**
     * 自定义日期格式
     *
     * @param date      LocalDate日期
     * @param formatter 自定义格式
     * @return 日期字符串
     */
    public static String dateFormatter(LocalDate date, String formatter) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern(formatter);
        return Objects.isNull(date) ? "" : dtf.format(date);
    }

    /**
     * 自定义日期格式
     *
     * @param date      LocalDateTime日期
     * @param formatter 自定义格式
     * @return 日期字符串
     */
    public static String dateFormatter(LocalDateTime date, String formatter) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern(formatter);
        return Objects.isNull(date) ? "" : dtf.format(date);
    }

    /**
     * 把dateString转换成LocalDate类型,只能格式化日期
     *
     * @param dateStr 日期字符串
     * @return LocalDate
     */
    public static LocalDate convertStringToLocalDate(String dateStr, DateTimeFormatter formatter) {
        return Objects.isNull(dateStr) ? null : LocalDate.parse(dateStr, formatter);
    }

    /**
     * 把dateString转换成LocalTime类型,只能格式化时间
     *
     * @param dateStr 日期字符串
     * @return LocalTime
     */
    public static LocalTime convertStringToLocalTime(String dateStr, DateTimeFormatter formatter) {
        return Objects.isNull(dateStr) ? null : LocalTime.parse(dateStr, formatter);
    }

    /**
     * 把dateString转换成LocalDateTime类型,只能格式化时间
     *
     * @param dateStr 日期字符串
     * @return LocalDateTime
     */
    public static LocalDateTime convertStringToLocalDateTime(String dateStr, DateTimeFormatter formatter) {
        return Objects.isNull(dateStr) ? null : LocalDateTime.parse(dateStr, formatter);
    }

    /**
     * 获取传入日期为星期几
     *
     * @param date 日期Date
     * @return 星期几
     */
    public static int weekDay(LocalDate date) {
        return date.getDayOfWeek().getValue();
    }

    public static String chineseWeekDay(LocalDate date) {
        int weekDay = weekDay(date);
        return chineseWeekDay(weekDay);
    }

    public static String chineseWeekDay(int weekDay) {
        String[] weeks = {"星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"};
        return weeks[weekDay - 1];
    }

    /**
     * 获取前一天的日期
     *
     * @return 前一天的日期
     */
    public static LocalDate preDay() {
        return LocalDate.now().minusDays(1);
    }

    /**
     * 获取前N天的日期
     *
     * @return 前N天的日期
     */
    public static LocalDate preDay(int days) {
        return LocalDate.now().minusDays(days);
    }

    /**
     * 获取后一天的日期
     *
     * @return 后一天的日期
     */
    public static LocalDate nextDay() {
        return LocalDate.now().plusDays(1);
    }

    /**
     * 获取后N天的日期
     *
     * @return 后N天的日期
     */
    public static LocalDate nextDay(int days) {
        return LocalDate.now().plusDays(days);
    }

    /**
     * 计算两个日期的天数差
     *
     * @param beginDate 开始日期
     * @param endDate   截止日期
     * @return 相差多少天
     */
    public static Long getDaysBetween(LocalDate beginDate, LocalDate endDate) {
        return endDate.toEpochDay() - beginDate.toEpochDay();
    }

    /**
     * 根据传入日期转换成默认时区的LocalDate
     *
     * @param date 日期
     * @return LocalDate
     */
    public static LocalDate asLocalDate(Date date) {
        return asLocalDate(date, ZoneId.systemDefault());
    }

    /**
     * 根据传入日期转换成默认时区的LocalDate
     *
     * @param date 日期
     * @param zone 时区
     * @return LocalDate
     */
    public static LocalDate asLocalDate(Date date, ZoneId zone) {
        if (date == null) {
            return null;
        }
        if (date instanceof java.sql.Date) {
            return ((java.sql.Date) date).toLocalDate();
        } else {
            return Instant.ofEpochMilli(date.getTime()).atZone(zone).toLocalDate();
        }
    }

    /**
     * 根据传入日期转换成默认时区的LocalDateTime
     *
     * @param date 日期
     * @return LocalDateTime
     */
    public static LocalDateTime asLocalDateTime(Date date) {
        return asLocalDateTime(date, ZoneId.systemDefault());
    }

    /**
     * 根据传入日期转换成默认时区的LocalDateTime
     *
     * @param date 日期
     * @param zone 时区
     * @return LocalDateTime
     */
    public static LocalDateTime asLocalDateTime(Date date, ZoneId zone) {
        if (date == null) {
            return null;
        }
        if (date instanceof java.sql.Timestamp) {
            return ((java.sql.Timestamp) date).toLocalDateTime();
        } else {
            return Instant.ofEpochMilli(date.getTime()).atZone(zone).toLocalDateTime();
        }
    }

    /**
     * Object对象转成java.util.Date
     *
     * @param date 日期
     * @return java.util.Date
     */
    public static Date asUtilDate(Object date) {
        return asUtilDate(date, ZoneId.systemDefault());
    }

    /**
     * 从各种日期格式创建{@link Date} 当前支持的有:
     * <ul>
     * <li>{@link Date}
     * <li>{@link java.sql.Date}
     * <li>{@link java.sql.Timestamp}
     * <li>{@link LocalDate}
     * <li>{@link LocalDateTime}
     * <li>{@link ZonedDateTime}
     * <li>{@link Instant}
     * </ul>
     * <p>
     * Object对象转成java.util.Date
     *
     * @param date 日期
     * @param zone 时区,只有LocalDate或LocalDateTime时候才用到
     * @return java.util.Date
     */
    public static Date asUtilDate(Object date, ZoneId zone) {
        if (date == null) {
            return null;
        } else if (date instanceof java.sql.Date || date instanceof java.sql.Timestamp) {
            return new Date(((Date) date).getTime());
        } else if (date instanceof Date) {
            return (Date) date;
        } else if (date instanceof LocalDate) {
            return Date.from(((LocalDate) date).atStartOfDay(zone).toInstant());
        } else if (date instanceof LocalDateTime) {
            return Date.from(((LocalDateTime) date).atZone(zone).toInstant());
        } else if (date instanceof ZonedDateTime) {
            return Date.from(((ZonedDateTime) date).toInstant());
        } else if (date instanceof Instant) {
            return Date.from((Instant) date);
        }
        throw new UnsupportedOperationException("Do not convert " + date.getClass().getName() + " to java.util.Date");
    }

    /**
     * 日期转换成Instant
     *
     * @param date 日期
     * @return Instant
     */
    public static Instant asInstant(Date date) {
        return date == null ? null : Instant.ofEpochMilli(date.getTime());
    }

    /**
     * 日期转换成ZonedDateTime
     *
     * @param date 日期
     * @return ZonedDateTime
     */
    public static ZonedDateTime asZonedDateTime(Date date) {
        return asZonedDateTime(date, ZoneId.systemDefault());
    }

    /**
     * 日期转换成ZonedDateTime
     *
     * @param date 日期
     * @param zone 时区
     * @return ZonedDateTime
     */
    public static ZonedDateTime asZonedDateTime(Date date, ZoneId zone) {
        return date == null ? null : asInstant(date).atZone(zone);
    }

    /**
     * 获取某个时间的毫秒值
     *
     * @param ldt 当前时间
     * @return 毫秒值
     */
    public static long getTimeMilli(LocalDateTime ldt) {
        return ldt.toInstant(ZoneOffset.ofHours(8)).toEpochMilli();
    }

    /**
     * 时间戳转LocalDateTime
     *
     * @param timestamp 时间戳
     * @return LocalDateTime
     */
    public static LocalDateTime getLocalDateTimeOfTimestamp(long timestamp) {
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());
    }

}
